<?php

declare(strict_types=1);

namespace MultiWorker;

use BadMethodCallException;
use MultiWorker\Exception\ProcessException;
use MultiWorker\Constract\LoggerInterface;

abstract class Process
{   
    /**
     * 当前进程pid
     *
     * @var int
     */
    protected $pid;

    /**
     * 管道操作对象
     *
     * @var Pipeline
     */
    protected $pipe;

    /**
     * handler.
     *
     * @var mixed
     */
    protected $handler;

    /**
     * config array.
     *
     * @var array
     */
    protected $config = [];

    /**
     * 最大可使用内存(MB)
     *
     * @var integer
     */
    protected $maxMemoryLimit = -1;

    /**
     * process loop sleep time.
     *
     * @var integer
     */
    protected $loopMicrotime = 10000;

    /**
     * logger instance.
     *
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * Process Constructor.
     * 
     * @return void
     */
    public function __construct($config = [])
    {
        if (empty($this->pid)) {
            $this->setPid(null);
        }
        $this->config         = array_merge($this->config,$config);
        $this->maxMemoryLimit = $this->config['max_memory_limit'] ?? -1;
        $this->loopMicrotime  = $this->config['loop_microtime'] ?? 10000;
    }

    /**
     * 设置进程id
     *
     * @param integer $pid
     * @return void
     */
    public function setPid ($pid)
    {
        if (is_null($pid)) {
            $pid = posix_getpid();
        }
        $this->pid = $pid;
    }

    /**
     * 获取执行进程id
     *
     * @return integer
     */
    public function getPid ()
    {
        return $this->pid;
    }

    /**
     * 获取管道对象
     *
     * @return Pipeline
     */
    public function getPipe (): Pipeline
    {
        if (!$this->pipe) {
            $this->makePipe();
        }
        return $this->pipe;
    }

    /**
     * 创建管道对象
     *
     * @return void
     */
    public function makePipe ()
    {
        $name = (string)$this->pid;
        $this->pipe = new Pipeline(
            $name,
            $this->config['runtime_path'] ?? null,
            $this->config['pipe_prefix'] ?? null
        );
    }

    /**
     * 停止进程.
     *
     * @return boolean
     */
    public function stop (): bool
    {
        $this->getPipe()->clear();
        if (!posix_kill($this->pid,SIGKILL)) {
            throw new ProcessException("{$this->pid} process kill error.");
        }
        return true;
    }

    /**
     * set logger.
     *
     * @param Logger $logger
     * @return self
     */
    public function setLogger (LoggerInterface $logger): self
    {
        $this->logger = $logger;
        return $this;
    }

    /**
     * get logger.
     *
     * @return Logger
     */
    public function logger (): LoggerInterface
    {
        return $this->logger;
    }
    
    /**
     * Process __call.
     *
     * @param string $method
     * @param array $arguments
     * @return mixed
     */
    public function __call ($method,$arguments)
    {
        if (method_exists($this->getPipe(),$method)) {
            return $this->getPipe()->{$method}(...$arguments);
        }
        throw new BadMethodCallException(__CLASS__ . " call {$method} does not exist.");
    }
}